package com.code9xs.security;

import com.code9xs.exception.CaptchaException;
import com.code9xs.util.Const;
import com.code9xs.util.RedisUtil;
import com.code9xs.util.Result;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.validation.BindingResult;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

@Component
public class CaptchaFilter extends OncePerRequestFilter {

	@Autowired
	RedisUtil redisUtil;

	@Autowired
	LoginFailureHandler loginFailureHandler;

	@Override
	protected void doFilterInternal(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, FilterChain filterChain) throws ServletException, IOException {

		String url = httpServletRequest.getRequestURI();

		if ("/api/v1/login".equals(url) && httpServletRequest.getMethod().equals("POST")) {

			try{
				// 校验验证码
				validate(httpServletRequest);
			} catch (CaptchaException e) {

				// 交给认证失败处理器
				loginFailureHandler.onAuthenticationFailure(httpServletRequest, httpServletResponse, e);
			}
		}

		filterChain.doFilter(httpServletRequest, httpServletResponse);
	}

	// 校验验证码逻辑
	private void validate(HttpServletRequest httpServletRequest) {

		String code = httpServletRequest.getParameter("code");
		String key = httpServletRequest.getParameter("token");

		if (code == null || key == null) {
			throw new CaptchaException("验证码错误");
		}

		if (!code.equals(redisUtil.hget(Const.CAPTCHA_KEY, key))) {
			throw new CaptchaException("验证码错误");
		}

		// 一次性使用
		redisUtil.hdel(Const.CAPTCHA_KEY, key);
	}

    @Slf4j
    @RestControllerAdvice
    public static class GlobalExceptionHandler {

        //

        // 实体校验异常捕获
        @ResponseStatus(HttpStatus.BAD_REQUEST)
        @ExceptionHandler(value = MethodArgumentNotValidException.class)
        public Result handler(MethodArgumentNotValidException e) {

            BindingResult result = e.getBindingResult();
            ObjectError objectError = result.getAllErrors().stream().findFirst().get();

            log.error("实体校验异常：----------------{}", objectError.getDefaultMessage());
            return Result.fail(objectError.getDefaultMessage());
        }

        @ResponseStatus(HttpStatus.BAD_REQUEST)
        @ExceptionHandler(value = IllegalArgumentException.class)
        public Result handler(IllegalArgumentException e) {
            log.error("Assert异常：----------------{}", e.getMessage());
            return Result.fail(e.getMessage());
        }

        @ResponseStatus(HttpStatus.BAD_REQUEST)
        @ExceptionHandler(value = RuntimeException.class)
        public Result handler(RuntimeException e) {
            log.error("运行时异常：----------------{}", e.getMessage());
            return Result.fail(e.getMessage());
        }

    }
}
